package com.itheima.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dto.DishDto;
import com.itheima.dto.SetmealDto;
import com.itheima.po.Category;
import com.itheima.po.Dish;
import com.itheima.po.R;
import com.itheima.po.Setmeal;
import com.itheima.service.CatetoryService;
import com.itheima.service.SetmealServcie;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author Andy
 * @Description //TODO SetmealController
 * @Date 2022/3/18 9:55 上午
 * @Version 1.0
 **/
@RestController
@RequestMapping("/setmeal")
@Api(tags = "套餐相关接口")
public class SetmealController {

    @Autowired
    private SetmealServcie setmealServcie;

    @Autowired
    private CatetoryService catetoryService;

    @PostMapping("")
    @CacheEvict(value = "setmealCache", allEntries = true)
    @ApiOperation(value = "新增套餐接口")
    public R<String> save(@RequestBody SetmealDto setmealDto) {
        setmealServcie.saveWithDish(setmealDto);
        return R.success("添加成功");
    }

//    @GetMapping("/page")
//    public R<Page<SetmealDto>> page(Integer page, Integer pageSize, String name) {
//
////        从数据库中查询Page<Setmeal>然后根据setmeal的ID查询分类名字，
////        然后Page<SetmealDto>组装出来，返回给前端
//
////返回的数据是SetmealDto 套餐数据与分类名字 组装成Page<SetmealDto>
////        1 从数据库中查询套餐的数据Page<Setmeal>
//        Page<Setmeal> setmealPage = new Page<>(page, pageSize);
//        LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        lambdaQueryWrapper.like(StringUtils.isNotBlank(name), Setmeal::getName, name);
//        lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);
//        setmealServcie.page(setmealPage, lambdaQueryWrapper);
////        2 根据Setmeal的id查询出分类的名字
//        Page<SetmealDto> setmealDtoPage = new Page<>(page, pageSize);
//        BeanUtils.copyProperties(setmealPage, setmealDtoPage, "records");
//        List<Setmeal> records = setmealPage.getRecords();
//        //        3 组装Page<SetmealDto>返回给前端
//        setmealDtoPage.setRecords(new ArrayList<>());
//        for (Setmeal setmeal :
//                records) {
//            Category category = catetoryService.getById(setmeal.getCategoryId());
//            SetmealDto setmealDto = new SetmealDto();
//            BeanUtils.copyProperties(setmeal, setmealDto);
//            setmealDto.setCategoryName(category.getName());
//            setmealDtoPage.getRecords().add(setmealDto);
//        }
//        return R.success(setmealDtoPage);
//    }

    @GetMapping("/page")
    @ApiOperation(value = "套餐分页查询接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page",value = "页码",required = true),
            @ApiImplicitParam(name = "pageSize",value = "每页记录数",required = true),
            @ApiImplicitParam(name = "name",value = "套餐名称",required = false)
    })
    public R<Page<SetmealDto>> page(Integer page, Integer pageSize, String name){
//        根据查询条件查询出菜品数据
        Page<Setmeal> setmealPage = new Page<>(page, pageSize); // 从数据库中查询出来
        LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        "" " " null "     "
        lambdaQueryWrapper.like(StringUtils.isNotBlank(name), Setmeal::getName, name);
        lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);
        setmealServcie.page(setmealPage, lambdaQueryWrapper);
//        根据菜品数据中的分类ID查询分类数据
//        把Dish的值复制给DishDto
//       因为 dishPage没有categoryName，所以需要把dishPage的值复制给dishDtoPage

        Page<SetmealDto> setmealDtoPage = new Page<>(); // 真正要返回给前端的
       /* dishDtoPage.setRecords(new ArrayList<>());
//        从数据库中差回来的分页的dish数据
        List<Dish> records = dishPage.getRecords();
        for (int i =0 ; i< records.size();i++){
            DishDto dishDto = new DishDto();
            dishDto.setCategoryId(records.get(i).getCategoryId());
            dishDto.setImage(records.get(i).getImage());
            dishDto.setCategoryId(records.get(i).getCategoryId());
            dishDto.setCategoryId(records.get(i).getCategoryId());
            dishDto.setCategoryId(records.get(i).getCategoryId());
            dishDto.setCategoryId(records.get(i).getCategoryId());
            dishDtoPage.getRecords().add(dishDto);
        }
        dishDtoPage.setTotal(dishPage.getTotal());
        dishDtoPage.setCurrent(dishPage.getCurrent());
        dishDtoPage.setSize(dishPage.getSize());

        */
//        忽略records，那么复制完后records没有复制过来，所以后面需要单独处理records的值
        BeanUtils.copyProperties(setmealPage, setmealDtoPage, "records");
//        虽然Page<DishDto> dishDtoPage = new Page<>(); 在初始化的时候records设置了初始值，但是并
//        不是new ArrayList<>()，所以在添加的时候报错。
        setmealDtoPage.setRecords(new ArrayList<>());
//        给每个菜品的DTO设置分类名字
        List<Setmeal> records = setmealPage.getRecords();
        for (Setmeal setmeal : records) {
            SetmealDto setmealDto = new SetmealDto();
            BeanUtils.copyProperties(setmeal, setmealDto);
            Category category = catetoryService.getById(setmealDto.getCategoryId());
            if (null != category){
                setmealDto.setCategoryName(category.getName());
            }
            setmealDtoPage.getRecords().add(setmealDto);
        }

        return R.success(setmealDtoPage);
    }

//    步骤 ids单个删除与批量删除
//    售卖中的套餐不能删除
//    所有要删除的套餐为停售状态，则删除套餐数据以及套餐菜品数据
//Whether all the entries inside the cache(s) are removed.
//    无论如何 所有的在redis内部的数据会被删除
//    By default, only the value under the associated key is removed.
//    默认，仅仅是与key有关联的数据
//    Note that setting this parameter to true and specifying a key is not allowed.
//    注意，设置这个参数为true，且仅仅指定一个key是不被允许的。
    @DeleteMapping("")
//    key 是分类ID与状态，但是从参数中无法获取，
    @CacheEvict(value = "setmealCache", allEntries = true) // 作用删除所有setmealCache开头key
    @ApiOperation(value = "套餐删除接口")
    public R<String> delete(@RequestParam List<Long> ids){
        setmealServcie.deleteWithDish(ids);
        return R.success("删除成功");
    }

//    Request URL: http://localhost:8080/setmeal/list?categoryId=1413342269393674242&status=1
//    Request Method: GET

    /*
    需求梳理：需要给APP端的套餐list接口添加缓存处理，同时后端如果对套餐进行增删改会影响到APP端套餐list
    步骤：1 list使用spring cache添加@Cacheable注解，从数据库中读取列表数据，放入到redis中。
                当首次读取的时候，redis中没有数据，则从数据库中读取后放入redis，之后redis中有数据了
                则直接查询redis中的数据，不会再查询数据库了，这样redis的读写性能是数据库的两个数量级以上
                key value
                spring cache redis key 是有springcache中的value+key进行拼接而得到
                key: setmealCache+categoryId+status  setmealCache的作用，给缓存添加一个前缀，到时候对缓存进行批量处理时方便
                value: R<List<Setmeal>>
          总结，所有加springcache注解的方法其返回值，直接作为存储到redis中value值。
         2 套餐管理的增删改接口在被使用时，对redis中存储套餐列表数据进行清除
         利用@CacheEvict注解来清理所有的列表相关缓存


         =-------------------------
         SetmealControllerEnhance 通过cglib动态代理实现组件动态生成一个类，
         public class SetmealControllerEnhance extends SetmealController{
            @Autowired
            private redisTemplate redisTempalte;
            public R<List<Setmeal>> list(Long categoryId, Integer status) {
                //...通过反射，获取注解，拿到注解中value与key的值
                String key = getKeyBy反射与注解解析();
                Object value = redisTempalte.get(key);
                if(value == null){
                    return super.list(categoryId,  status);
                }
                return value;
            }
         }
     */

    @GetMapping("/list")
    @Cacheable(value = "setmealCache", key = "#categoryId+'_'+#status") //如果注解起作用了，redis中有数据，则这个list方法不会被调用，而是直接走redis缓存
    @ApiOperation(value = "套餐条件查询接口")
    public R<List<Setmeal>> list(Long categoryId, Integer status) {
        LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(null != categoryId, Setmeal::getCategoryId, categoryId);
        lambdaQueryWrapper.eq(null != status, Setmeal::getStatus, status);
        lambdaQueryWrapper.orderByAsc(Setmeal::getUpdateTime);
//        service触发查询
        List<Setmeal> list = setmealServcie.list(lambdaQueryWrapper);
        return R.success(list);
    }

}
